package bb.lanxing.devicelist.fragment

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.Button
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import bb.lanxing.App
import bb.lanxing.R
import bb.lanxing.activity.base.BaseActivity
import bb.lanxing.activity.bluetooth.BikeTrainerStatusActivity
import bb.lanxing.activity.bluetooth.Cadence01StatusActivity
import bb.lanxing.activity.bluetooth.CadenceStatusActivity
import bb.lanxing.activity.bluetooth.CrossTrainerStatusActivity
import bb.lanxing.activity.bluetooth.HeartRate01StatusActivity
import bb.lanxing.activity.bluetooth.HeartRateBeltStatusActivity
import bb.lanxing.activity.bluetooth.HeartRateStatusActivity
import bb.lanxing.activity.bluetooth.IndoorBikeStatusActivity
import bb.lanxing.activity.bluetooth.PowerRateStatusActivity
import bb.lanxing.activity.bluetooth.RowerStatusActivity
import bb.lanxing.activity.bluetooth.SmartAssistDeviceActivity
import bb.lanxing.activity.bluetooth.SwitchableCadenceStatusActivity
import bb.lanxing.activity.bluetooth.light.LightDeviceActivity
import bb.lanxing.calc.data.DisplayPoint
import bb.lanxing.databinding.FragmentDevicesListBinding
import bb.lanxing.device.sgdevcie.sensors.SearchBleSensorActivity
import bb.lanxing.device.sgdevcie.xpair.XPairLauncher
import bb.lanxing.devicelist.XZDeviceListViewModel
import bb.lanxing.devicelist.XZOtherDeviceActivity
import bb.lanxing.devicelist.adapter.DevicesBikeComputerAdapter
import bb.lanxing.devicelist.adapter.DevicesSensorAdapter
import bb.lanxing.lib.devices.api.ConnectionListener
import bb.lanxing.lib.devices.api.DeviceManager
import bb.lanxing.lib.devices.api.DeviceStateListener
import bb.lanxing.lib.devices.api.SmartDevice
import bb.lanxing.lib.devices.base.DeviceContext
import bb.lanxing.lib.devices.core.utils.DeviceHelper
import bb.lanxing.lib.kt.model.CadenceData
import bb.lanxing.manager.RemoteServiceManager
import bb.lanxing.manager.RemoteServiceManager.DisplayPointChangedListener
import bb.lanxing.model.database.Device
import bb.lanxing.mvvm.base.BaseDBFragment
import bb.lanxing.util.DensityUtil
import bb.lanxing.util.Log
import bb.lanxing.util.OnDeviceBondStateChangeListener
import bb.lanxing.util.ui.RecyclerViewSpaceItemDecoration
import bb.lanxing.view.dialog.CommonDialogFragment
import com.bes.bessdk.BesSdkConstants
import com.bes.bessdk.scan.BtHeleper
import com.bes.bessdk.service.base.BesServiceListener
import com.bes.sdk.device.HmDevice
import com.bes.sdk.message.Constants
import com.bes.sdk.utils.DeviceProtocol
import com.besall.allbase.bluetooth.service.Protocol.ProtocolConstants
import com.besall.allbase.view.activity.chipstoollevel4.protocol.ProtocolActivity
import com.besall.allbase.view.activity.chipstoollevel4.protocol.ProtocolPresenter
import com.blankj.utilcode.util.ConvertUtils
import com.github.mikephil.charting.utils.Utils
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class DevicesListFragment : BaseDBFragment<FragmentDevicesListBinding>(R.layout.fragment_devices_list), ConnectionListener, DeviceStateListener, BesServiceListener {
  private val TAG = "DevicesListFragment"
  private val bikeComputerAdapter: DevicesBikeComputerAdapter
  private var displayPointChangedListener: DisplayPointChangedListener? = null
  private val isNeedTitleShow = true
  private val onDeviceBondStateChangeListener: OnDeviceBondStateChangeListener
  private val sensorAdapter = DevicesSensorAdapter()
  private lateinit var xPairLauncher: XPairLauncher
  private val viewModel by viewModels<XZDeviceListViewModel>()
  override fun onDeviceStateChanged(smartDevice: SmartDevice, i: Int) {}
  private var isRegister = false
  private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
      intent?.apply {
        val status = getIntExtra(Constants.KEY_CONN_STATE, BesSdkConstants.BES_CONNECT_ERROR)
        if (status == BesSdkConstants.BES_CONNECT_SUCCESS) {
          val device = getParcelableExtra(Constants.KEY_DEVICE) as? SmartDevice
          device?.apply {
            refreshList()
            saveNewConnectedDevice(this)
          }
        }
      }
    }
  }

  init {
    sensorAdapter.setOnItemClickListener { baseQuickAdapter, _, i ->
      val item = baseQuickAdapter.getItem(i)
      val smartDevice = item as SmartDevice
      if (activity != null) {
        viewModel.checkPermission(
          activity as BaseActivity
        ) {
          when (smartDevice.type) {
            SmartDevice.TYPE_CADENCE -> {
              val intent = Intent(context, CadenceStatusActivity::class.java)
              intent.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent)
            }

            SmartDevice.TYPE_HEARTRATE -> {
              val intent2 = Intent(context, HeartRateStatusActivity::class.java)
              intent2.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent2.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent2)
            }

            SmartDevice.TYPE_POWERRATE -> {
              val intent2 = Intent(context, PowerRateStatusActivity::class.java)
              intent2.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent2.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent2)
            }

            SmartDevice.TYPE_BIKE_TRAINER -> {
              val intent2 = Intent(context, BikeTrainerStatusActivity::class.java)
              intent2.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent2.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent2)
            }

            SmartDevice.TYPE_INDOOR_BIKE -> {
              val intent2 = Intent(context, IndoorBikeStatusActivity::class.java)
              intent2.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent2.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent2)
            }

            SmartDevice.TYPE_CROSS_TRAINER -> {
              val intent2 = Intent(context, CrossTrainerStatusActivity::class.java)
              intent2.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent2.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent2)
            }

            SmartDevice.TYPE_ROWER -> {
              val intent2 = Intent(context, RowerStatusActivity::class.java)
              intent2.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent2.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent2)
            }

            SmartDevice.TYPE_Q1 -> {
              val intent3 = Intent(context, SmartAssistDeviceActivity::class.java)
              intent3.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent3.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent3)
            }

            SmartDevice.TYPE_HEARTRATE_BELT -> {
              val intent4 = Intent(context, HeartRateBeltStatusActivity::class.java)
              intent4.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent4.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent4)
            }

            SmartDevice.TYPE_VORTEX_CADENCE -> {
              val intent5 = Intent(context, SwitchableCadenceStatusActivity::class.java)
              intent5.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent5.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent5)
            }

            SmartDevice.TYPE_CADENCE01 -> {
              val intent5 = Intent(context, Cadence01StatusActivity::class.java)
              intent5.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent5.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent5)
            }

            SmartDevice.TYPE_LIGHT -> {
              val intent6 = Intent(context, LightDeviceActivity::class.java)
              intent6.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent6.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent6)
            }

            SmartDevice.TYPE_HEART_RATE01 -> {
              val intent2 = Intent(context, HeartRate01StatusActivity::class.java)
              intent2.putExtra("EXTRA_DEVICE_ADDRESS", smartDevice.address)
              intent2.putExtra("EXTRA_DEVICE_TYPE", smartDevice.type)
              startActivity(intent2)
            }

            else -> {
              //TODO:sun
            }
          }/* else if (DeviceUtils.isDfuDevice(smartDevice)) {
                    val companion: UpdateDeviceIntroActivity.Companion = UpdateDeviceIntroActivity.Companion
                    val requireActivity: FragmentActivity = requireActivity()
                    Intrinsics.checkNotNullExpressionValue(requireActivity, "requireActivity()")
                    val address: String = smartDevice.getAddress()
                    Intrinsics.checkNotNullExpressionValue(address, "device.address")
                    val name: String = smartDevice.getName()
                    Intrinsics.checkNotNullExpressionValue(name, "device.name")
                    companion.start(requireActivity, address, name)
                } else {
                    val intent7 = Intent(context, XossHeartRateX2ProActivity::class.java)
                    intent7.putExtra(BaseSensorActivity.DEVICE_ADDRESS, smartDevice.getAddress())
                    intent7.putExtra(BaseSensorActivity.DEVICE_TYPE, smartDevice.getType())
                    intent7.putExtra(BaseSensorActivity.DEVICE_NAME, smartDevice.getName())
                    startActivity(intent7)
                }*/
        }
      }
    }
    bikeComputerAdapter = DevicesBikeComputerAdapter()
    bikeComputerAdapter.addChildClickViewIds(R.id.btn_unbind)
    bikeComputerAdapter.setOnItemChildClickListener { _, _, i ->
      unBindDeviceCmd()
    }
    bikeComputerAdapter.setOnItemLongClickListener { _, _, i ->
      val smartDevice = bikeComputerAdapter.getItem(i)
      val address = smartDevice.address
      showDeleteConfirmDialog(address)
      true
    }
    bikeComputerAdapter.setOnItemClickListener { _, _, i ->
      val smartDevice = bikeComputerAdapter.getItem(i)
      val intent = Intent(activity, ProtocolActivity::class.java)
      val hmDevice = HmDevice()
      hmDevice.deviceName = smartDevice.name
      hmDevice.preferredProtocol = DeviceProtocol.PROTOCOL_BLE
      hmDevice.bleAddress = smartDevice.address
      hmDevice.rssi = smartDevice.rssi
      val bundle = Bundle()
      bundle.putSerializable("HM_DEVICE", hmDevice)
      intent.putExtra("BUNDLE_CONTENT", bundle)
      intent.putExtra("is_from_devicelist", 1)
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
      startActivity(intent);

    }
    onDeviceBondStateChangeListener = object : OnDeviceBondStateChangeListener {
      override fun onBondFailed(address: String) {
      }

      override fun onBonded(address: String) {
      }

      override fun onBonding(address: String) {
      }

      override fun targetAddress(): String {
        return ""
      }

      override fun onBondLost(address: String) {
      }
    }
    displayPointChangedListener = DisplayPointChangedListener { displayPoint ->
      if (null == displayPoint || null == activity) {
        return@DisplayPointChangedListener
      }
      runOnUIThread {
        refreshDevicesList(displayPoint)
      }
    }
  }

  override fun onResume() {
    super.onResume()
    ImmersionBar.with(this).statusBarColor(R.color.white).statusBarDarkFont(true).init()
    registerListener()
    initReceiver()
  }

  private fun registerListener() {
    if (!isRegister) {
      isRegister = true
      if (displayPointChangedListener != null) {
        RemoteServiceManager.getInstance().registerDisplayPointChangedListener(
          displayPointChangedListener
        )
      }
    }
    val protocolPresenter = ProtocolPresenter.getInstance()
    protocolPresenter.setProtocolServiceListener(this)
  }

  private fun unRegister() {
    if (isRegister) {
      isRegister = false
      if (displayPointChangedListener != null) {
        RemoteServiceManager.getInstance().unregisterDisplayPointChangedListener(
          displayPointChangedListener
        )
      }
    }
  }

  override fun onCreate(bundle: Bundle?) {
    super.onCreate(bundle)
    registerLifeCycle()
    DeviceHelper.registerConnectionStateListener(this)
    DeviceHelper.registerDeviceStateListener(this)
    lifecycleScope.launch(Dispatchers.IO) {
      DeviceContext.startAndRefreshAutoConnector()
      withContext(Dispatchers.Main) {
        refreshList()
      }
    }
  }

  override fun initView(binding: FragmentDevicesListBinding) {
    if (isNeedTitleShow) {
      binding.imgBack.setOnClickListener {
        finish()
      }
    } else {
      dismissTitle()
    }

    binding.rvMySensors.layoutManager = GridLayoutManager(context, 2)
    binding.rvMySensors.addItemDecoration(
      RecyclerViewSpaceItemDecoration(
        DensityUtil.dp2px(
          10.0f
        ), 2
      )
    )
    binding.addNewSensors.setOnClickListener(this::onClickAddNewSensors)
    binding.addNewBikeComputer.setOnClickListener(this::onGoNewBikeComputerConnect)
//        binding.connectOtherDevices.setOnClickListener(this::onGoOtherDevice)

    val sensorAnimator = DefaultItemAnimator()
    sensorAnimator.supportsChangeAnimations = false
    binding.rvMySensors.itemAnimator = sensorAnimator
    binding.rvMySensors.adapter = sensorAdapter;
    binding.rvMyBikeComputers.layoutManager = LinearLayoutManager(
      context, RecyclerView.VERTICAL, true
    )

    val computerAnimator = DefaultItemAnimator()
    computerAnimator.supportsChangeAnimations = false
    binding.rvMyBikeComputers.adapter = bikeComputerAdapter;
    binding.rvMyBikeComputers.itemAnimator = computerAnimator
  }

  private fun dismissTitle() {
    val binding = binding
    if (binding != null) {
      binding.toolbar.visibility = View.INVISIBLE
    }
  }

  override fun onPause() {
    super.onPause()
    unRegister()
    unRegisterReceiver()
  }

  override fun onConnectionStateChanged(smartDevice: SmartDevice, newState: Int, errCode: Int) {
    Log.i(TAG, "wangsm_bt,deviceConnectListener, onConnectionStateChanged $newState")
    runOnUIThread {
      refreshList()
    }
    when (newState) {
      DeviceManager.STATE_CONNECTED -> {
        Log.d(TAG, "wangsm_bt,deviceConnectListener, on connected")
        saveNewConnectedDevice(smartDevice)
      }

      DeviceManager.STATE_DISCONNECTED -> {
        Log.d(TAG, "wangsm_bt,deviceConnectListener, on disconnected")
      }

      8 -> {
        Log.d(TAG, "wangsm_bt,deviceConnectListener, service discovered")
      }
    }
  }

  override fun onDestroy() {
    super.onDestroy()
    DeviceHelper.unregisterConnectionStateListener(this)
    DeviceHelper.unregisterDeviceStateListener(this)
  }

  private fun refreshList() {
    Log.d(TAG, "wangsm_bt,refreshList")

    val boundedSensors = viewModel.boundedSensorDevices
    if (boundedSensors.isEmpty()) {
      binding.txtSensorTitle.visibility = View.GONE
    } else {
      binding.txtSensorTitle.visibility = View.VISIBLE
      binding.lineSeparator.visibility = View.VISIBLE
    }
    this.sensorAdapter.setList(boundedSensors)

    val boundedComputers = viewModel.boundedComputerDevices
    Log.d(TAG, "wangsm_bt,refreshList,get the boundedcomputerDevices")
    if (boundedComputers.isEmpty()) {
      binding.txtComputerTitle.visibility = View.GONE
    } else {
      binding.txtComputerTitle.visibility = View.VISIBLE
      binding.lineSeparator.visibility = View.VISIBLE
    }
    this.bikeComputerAdapter.setList(boundedComputers);
  }

  private fun refreshDevicesList(displayPoint: DisplayPoint?) {
    if (displayPoint == null) {
      return
    }
    Log.i(TAG, "refreshDevicesList")
    //need to refresh bounded device
    refreshList()
    refreshSensorsData(displayPoint)
  }

  private fun refreshSensorsData(
    displayPoint: DisplayPoint
  ) {
    val cadenceData = CadenceData(System.currentTimeMillis())
    Log.d(TAG, "refreshSensorsData")
    cadenceData.cadence = displayPoint.getCadence(0)
    cadenceData.speed = displayPoint.getSpeed(Utils.DOUBLE_EPSILON)
    sensorAdapter.updateValue(0, cadenceData, 2)
    val heartrate = displayPoint.heartrate
    if (heartrate != null) {
      sensorAdapter.updateValue(heartrate, cadenceData, 3)
    }
  }

  private fun finish() {
    activity?.finish()
  }

  private fun onClickAddNewSensors(view: View) {
    viewModel.checkPermission(activity as BaseActivity) {
      val intent = Intent(activity, SearchBleSensorActivity::class.java)
      intent.putExtra("EXTRA_DEVICE_TYPE", SmartDevice.TYPE_SENSORS)
      startActivity(intent)
    }
  }

  fun onGoNewSensorConnect(view: View) {
    viewModel.checkPermission(
      activity as BaseActivity
    ) {
      val intent3 = Intent(requireActivity(), SearchBleSensorActivity::class.java)
      intent3.putExtra("EXTRA_DEVICE_TYPE", SmartDevice.TYPE_SENSORS)
      startActivity(intent3)
    }
  }

  private fun onGoNewBikeComputerConnect(view: View) {
    viewModel.checkPermission(activity as BaseActivity) {
      //the origin code.
      /*            DeviceTypeSheetFragment.newInstance(xPairLauncher)
                      .show(this@DevicesListFragment.childFragmentManager, "device_type")*/
      Log.d(TAG, "onGoNewBikeComputerConnect--- ");
      val intent = Intent(requireActivity(), ProtocolActivity::class.java)
      startActivity(intent)

    }
  }

  private fun onGoOtherDevice(view: View) {
    viewModel.checkPermission(
      activity as BaseActivity
    ) {
      val intent = Intent(requireActivity(), XZOtherDeviceActivity::class.java)
      startActivity(intent)
    }
  }

  private fun registerLifeCycle() {
    xPairLauncher = XPairLauncher(activity, requireActivity().activityResultRegistry)
    lifecycle.addObserver(xPairLauncher)
  }

  private fun saveNewConnectedDevice(device: SmartDevice) {
    if (Device.getByAddress(device.address, App.getContext().userId) == null) {
      val needAutoConnectTypes = Device.getNeedAutoConnectTypes()

      if (needAutoConnectTypes.contains(device.type)) {
        Device.storeOrReplaceDevice(
          device.type, device.address, device.name, device.rssi, device.scanRecord, SmartDevice.PROTOCOL_BLE, false, App.getContext().userId
        )
      }
    }
  }

  private fun unBindDeviceCmd() {
    ProtocolPresenter.getInstance()?.sendInfoData(ProtocolConstants.INFO_Unbind_BT, null)
  }

  private fun unBindFinish(address: String) {
    val protocolPresenter = ProtocolPresenter.getInstance()
    if (protocolPresenter != null) {
      Log.d(TAG, "unbind the device finish")
      BtHeleper.unBondedBleDevice(requireActivity(), address)
      Device.deleteByAddress(address)
    }
  }

  override fun onTotaConnectState(state: Boolean, hmDevice: HmDevice?) {
  }

  override fun onErrorMessage(msg: Int, hmDevice: HmDevice?) {
  }

  override fun onStateChangedMessage(msg: Int, msgStr: String?, hmDevice: HmDevice?) {
  }

  override fun onSuccessMessage(msg: Int, hmDevice: HmDevice?) {
    Log.d(TAG, "wangsm_bes,settings onSuccessMessage,msg: $msg")
    if (msg == Constants.APP_UNBIND_DEVICE_SUCCESS) {
      unBindFinish(hmDevice?.bleAddress ?: "")
    }
  }

  private fun showDeleteConfirmDialog(address: String) {
    val dialog = CommonDialogFragment(
      R.layout.dialog_delete_device, object : CommonDialogFragment.ViewListener {
        override fun bindView(v: View, dialogFragment: DialogFragment) {
          val cancelBtn = v.findViewById<Button>(R.id.negativeBtn)
          val sureBtn = v.findViewById<Button>(R.id.positiveBtn)
          cancelBtn?.apply {
            setOnClickListener {
              dialogFragment.dismissAllowingStateLoss()
            }
          }
          sureBtn?.apply {
            setOnClickListener {
              dialogFragment.dismissAllowingStateLoss()
              if (DeviceHelper.isConnected(address)) {
                unBindDeviceCmd()
              } else {
                BtHeleper.unBondedBleDevice(requireActivity(), address)
                Device.deleteByAddress(address)
              }
            }
          }
        }
      }).setMargin(ConvertUtils.dp2px(10f))
    dialog.setCancelable(false)
    dialog.show(childFragmentManager)
  }

  private fun initReceiver() {
    val filter = IntentFilter(Constants.ACTION_BES_BLE_CONNECT_STATE)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
      requireActivity().registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED)
    } else {
      requireActivity().registerReceiver(receiver, filter)
    }
  }

  private fun unRegisterReceiver() {
    requireActivity().unregisterReceiver(receiver)
  }
}